<template>
  <div>
    <el-row>
      <el-col :span="6">
        <div style="padding-bottom: 5px;">
          <el-link type="primary" @click="resetDefault()">{{ $t('load_test.report.set_default') }}</el-link>
        </div>
        <el-collapse v-model="activeNames" class="test-detail">
          <el-collapse-item name="users">
            <template v-slot:title>
              <div style="width: 100%">
                <span>{{ $t('load_test.report.ActiveThreadsChart') }}</span>
                <span style="float:right;">
                  <el-link type="primary" @click="selectAll( 'ActiveThreadsChart', $event)">
                    {{ $t('load_test.report.select_all') }}
                  </el-link>
                  /
                  <el-link type="default" @click="unselectAll('ActiveThreadsChart', $event)">
                     {{ $t('load_test.report.unselect_all') }}
                  </el-link>
                </span>
              </div>
            </template>
            <el-checkbox-group v-model="checkList['ActiveThreadsChart']"
                               @change="handleChecked('ActiveThreadsChart')">
              <div v-for="name in checkOptions['ActiveThreadsChart']" :key="name">
                <el-tooltip class="item" effect="dark"
                            :content="name"
                            :disabled="name.length < minLength"
                            placement="top">
                  <el-checkbox :label="name"/>
                </el-tooltip>
              </div>
            </el-checkbox-group>
          </el-collapse-item>
          <el-collapse-item name="transactions">
            <template v-slot:title>
              <div style="width: 100%">
                <span>{{ $t('load_test.report.TransactionsChart') }}</span>
                <span style="float:right;">
                  <el-link type="primary" @click="selectAll( 'TransactionsChart', $event)">
                    {{ $t('load_test.report.select_all') }}
                  </el-link>
                  /
                  <el-link type="default" @click="unselectAll('TransactionsChart', $event)">
                     {{ $t('load_test.report.unselect_all') }}
                  </el-link>
                </span>
              </div>
            </template>
            <el-checkbox-group v-model="checkList['TransactionsChart']" @change="handleChecked('TransactionsChart')">
              <div v-for="name in checkOptions['TransactionsChart']"
                   :key="name">
                <el-tooltip class="item" effect="dark"

                            :content="name"
                            :disabled="name.length < minLength"
                            placement="top">
                  <el-checkbox :label="name"/>
                </el-tooltip>
              </div>
            </el-checkbox-group>
          </el-collapse-item>
          <el-collapse-item name="responseTime">
            <template v-slot:title>
              <div style="width: 100%">
                <span>{{ $t('load_test.report.ResponseTimeChart') }}</span>
                <span style="float:right;">
                  <el-link type="primary" @click="selectAll( 'ResponseTimeChart', $event)">
                    {{ $t('load_test.report.select_all') }}
                  </el-link>
                  /
                  <el-link type="default" @click="unselectAll('ResponseTimeChart', $event)">
                     {{ $t('load_test.report.unselect_all') }}
                  </el-link>
                </span>
              </div>
            </template>
            <el-checkbox-group v-model="checkList['ResponseTimeChart']" @change="handleChecked('ResponseTimeChart')">
              <div v-for="name in checkOptions['ResponseTimeChart']"
                   :key="name">
                <el-tooltip class="item" effect="dark"
                            :content="name"
                            :disabled="name.length < minLength"
                            placement="top">
                  <el-checkbox :label="name"/>
                </el-tooltip>
              </div>
            </el-checkbox-group>
          </el-collapse-item>
          <el-collapse-item name="responseTimePercentiles">
            <template v-slot:title>
              <div style="width: 100%">
                <span>{{ $t('load_test.report.ResponseTimePercentilesChart') }}</span>
                <span style="float:right;">
                  <el-link type="primary" @click="selectAll( 'ResponseTimePercentilesChart', $event)">
                    {{ $t('load_test.report.select_all') }}
                  </el-link>
                  /
                  <el-link type="default" @click="unselectAll('ResponseTimePercentilesChart', $event)">
                     {{ $t('load_test.report.unselect_all') }}
                  </el-link>
                </span>
              </div>
            </template>
            <el-checkbox-group v-model="checkList['ResponseTimePercentilesChart']"
                               @change="handleChecked('ResponseTimePercentilesChart')">
              <div v-for="name in checkOptions['ResponseTimePercentilesChart']"
                   :key="name">
                <el-tooltip class="item" effect="dark"
                            :content="name"
                            :disabled="name.length < minLength"
                            placement="top">
                  <el-checkbox :label="name"/>
                </el-tooltip>
              </div>
            </el-checkbox-group>
          </el-collapse-item>
          <el-collapse-item :title="$t('load_test.report.ResponseCodeChart')" name="responseCode">
            <template v-slot:title>
              <div style="width: 100%">
                <span>{{ $t('load_test.report.ResponseCodeChart') }}</span>
                <span style="float:right;">
                  <el-link type="primary" @click="selectAll( 'ResponseCodeChart', $event)">
                    {{ $t('load_test.report.select_all') }}
                  </el-link>
                  /
                  <el-link type="default" @click="unselectAll('ResponseCodeChart', $event)">
                     {{ $t('load_test.report.unselect_all') }}
                  </el-link>
                </span>
              </div>
            </template>
            <el-checkbox-group v-model="checkList['ResponseCodeChart']" @change="handleChecked('ResponseCodeChart')">
              <div v-for="name in checkOptions['ResponseCodeChart']"
                   :key="name">
                <el-tooltip class="item" effect="dark"
                            :content="name"
                            :disabled="name.length < minLength"
                            placement="top">
                  <el-checkbox :label="name"/>
                </el-tooltip>
              </div>
            </el-checkbox-group>
          </el-collapse-item>
          <el-collapse-item :title="$t('load_test.report.LatencyChart')" name="latency">
            <template v-slot:title>
              <div style="width: 100%">
                <span>{{ $t('load_test.report.LatencyChart') }}</span>
                <span style="float:right;">
                  <el-link type="primary" @click="selectAll( 'LatencyChart', $event)">
                    {{ $t('load_test.report.select_all') }}
                  </el-link>
                  /
                  <el-link type="default" @click="unselectAll('LatencyChart', $event)">
                     {{ $t('load_test.report.unselect_all') }}
                  </el-link>
                </span>
              </div>
            </template>
            <el-checkbox-group v-model="checkList['LatencyChart']" @change="handleChecked('LatencyChart')">
              <div v-for="name in checkOptions['LatencyChart']"
                   :key="name">
                <el-tooltip class="item" effect="dark"
                            :content="name"
                            :disabled="name.length < minLength"
                            placement="top">
                  <el-checkbox :label="name"/>
                </el-tooltip>
              </div>
            </el-checkbox-group>
          </el-collapse-item>
          <el-collapse-item :title="$t('load_test.report.BytesThroughputChart')" name="bytes">
            <template v-slot:title>
              <div style="width: 100%">
                <span>{{ $t('load_test.report.BytesThroughputChart') }}</span>
                <span style="float:right;">
                  <el-link type="primary" @click="selectAll( 'BytesThroughputChart', $event)">
                    {{ $t('load_test.report.select_all') }}
                  </el-link>
                  /
                  <el-link type="default" @click="unselectAll('BytesThroughputChart', $event)">
                     {{ $t('load_test.report.unselect_all') }}
                  </el-link>
                </span>
              </div>
            </template>
            <el-checkbox-group v-model="checkList['BytesThroughputChart']"
                               @change="handleChecked('BytesThroughputChart')">
              <div v-for="name in checkOptions['BytesThroughputChart']"
                   :key="name">
                <el-tooltip class="item" effect="dark"
                            :content="name"
                            :disabled="name.length < minLength"
                            placement="top">
                  <el-checkbox :label="name"/>
                </el-tooltip>
              </div>
            </el-checkbox-group>
          </el-collapse-item>
          <el-collapse-item :title="$t('load_test.report.ErrorsChart')" name="errors">
            <template v-slot:title>
              <div style="width: 100%">
                <span>{{ $t('load_test.report.ErrorsChart') }}</span>
                <span style="float:right;">
                  <el-link type="primary" @click="selectAll( 'ErrorsChart', $event)">
                    {{ $t('load_test.report.select_all') }}
                  </el-link>
                  /
                  <el-link type="default" @click="unselectAll('ErrorsChart', $event)">
                     {{ $t('load_test.report.unselect_all') }}
                  </el-link>
                </span>
              </div>
            </template>
            <el-checkbox-group v-model="checkList['ErrorsChart']" @change="handleChecked('ErrorsChart')">
              <div v-for="name in checkOptions['ErrorsChart']"
                   :key="name">
                <el-tooltip class="item" effect="dark"
                            :content="name"
                            :disabled="name.length < minLength"
                            placement="top">
                  <el-checkbox :label="name"/>
                </el-tooltip>
              </div>
            </el-checkbox-group>
          </el-collapse-item>
        </el-collapse>
      </el-col>
      <el-col :span="18" v-loading="result.loading">
        <el-row>
          <el-col :span="24">
            <ms-chart ref="chart2"
                      v-if="refresh"
                      class="chart-config"
                      :options="totalOption"
                      @datazoom="changeDataZoom"
                      :autoresize="true"/>
          </el-col>
        </el-row>
        <el-row>
          <el-col :offset="2" :span="20">
            <el-table
              v-if="refresh"
              :data="tableData"
              stripe
              border
              style="width: 100%">
              <el-table-column label="Label" align="center">
                <el-table-column
                  prop="label"
                  label="Label"
                  sortable>
                </el-table-column>
              </el-table-column>
              <el-table-column label="Aggregate" align="center">
                <el-table-column
                  prop="avg"
                  label="Avg."
                  width="100"
                  sortable
                />
                <el-table-column
                  prop="min"
                  label="Min."
                  width="100"
                  sortable
                />
                <el-table-column
                  prop="max"
                  label="Max."
                  width="100"
                  sortable
                />
              </el-table-column>
              <el-table-column label="Range" align="center">
                <el-table-column
                  prop="startTime"
                  label="Start"
                  width="160"
                />
                <el-table-column
                  prop="endTime"
                  label="End"
                  width="160"
                />
              </el-table-column>
            </el-table>
          </el-col>
        </el-row>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
import {getPerformanceReportDetailContent, getSharePerformanceReportDetailContent,} from "@/api/load-test";

const color = ['#60acfc', '#32d3eb', '#5bc49f', '#feb64d', '#ff7c7c', '#9287e7', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];

const groupBy = function (xs, key) {
  return xs.reduce(function (rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

const CHART_MAP = [
  'ActiveThreadsChart',
  'TransactionsChart',
  'ResponseTimeChart',
  'ResponseTimePercentilesChart',
  'ResponseCodeChart',
  'ErrorsChart',
  'LatencyChart',
  'BytesThroughputChart',
];

export default {
  name: "TestDetails",
  components: {MsChart},
  props: ['report', 'export', 'isShare', 'shareId', 'planReportTemplate'],
  data() {
    return {
      result: {},
      activeNames: 'users',
      minLength: 35,
      loadOption: {},
      resOption: {},
      totalOption: {},
      responseCodes: [],
      checkList: CHART_MAP.reduce((result, curr) => {
        result[curr] = [];
        return result;
      }, {}),
      checkOptions: {},
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      refresh: true,
      tableData: [],
      baseOption: {
        color: color,
        grid: {
          // right: '35%' // 动态改这个值
        },
        title: {},
        tooltip: {
          show: true,
          trigger: 'axis',
          axisPointer: {
            type: 'cross'
          },
          confine: true,
          formatter: function (params, ticket, callback) {
            let result = "";
            let name = params[0].name;
            result += name + "<br/>";
            for (let i = 0; i < params.length; i++) {
              let seriesName = params[i].seriesName;
              if (seriesName.length > 100) {
                seriesName = seriesName.substring(0, 100);
              }
              let value = params[i].value;
              let marker = params[i].marker;
              result += marker + seriesName + ": " + value[1] + "<br/>";
            }

            return result;
          }
        },
        legend: {
          y: 'top',
        },
        xAxis: {boundaryGap: false},
        yAxis: [],
        dataZoom: [
          {
            type: 'inside',
            start: 0,
            end: 100
          },
          {
            start: 0,
            end: 20
          }
        ],
        series: []
      },
      seriesData: [],
      legend: [],
    };
  },
  methods: {
    resetDefault() {

      this.checkList['ActiveThreadsChart'] = ['ALL'];
      this.checkList['TransactionsChart'] = ['ALL'];
      this.checkList['ResponseTimeChart'] = ['ALL'];
      //
      this.checkList['ResponseTimePercentilesChart'] = [];
      this.checkList['ErrorsChart'] = [];
      this.checkList['LatencyChart'] = [];
      this.checkList['BytesThroughputChart'] = [];

      this.getTotalChart();
    },
    selectAll(name, e) {
      if (e) {
        e.stopPropagation(); // 阻止冒泡
      }
      this.seriesData = [];
      this.totalOption = {};
      this.baseOption.yAxis = [];
      this.legend = [];
      this.checkList[name] = this.checkOptions[name];

      this.getTotalChart();
    },
    unselectAll(name, e) {
      if (e) {
        e.stopPropagation(); // 阻止冒泡
      }
      this.seriesData = [];
      this.totalOption = {};
      this.baseOption.yAxis = [];
      this.legend = [];
      if (name) {
        this.checkList[name] = [];
        this.getTotalChart();
        return;
      }
      for (const name in this.checkList) {
        this.checkList[name] = [];
      }
    },
    handleChecked(name) {

      this.getTotalChart();

      this.refresh = false;
      this.$nextTick(() => {
        this.refresh = true;
      });
    },
    initTableData() {
      for (const name of CHART_MAP) {
        this.getCheckOptions(name);
      }

      this.resetDefault();
    },
    getCheckOptions(reportKey) {
      if (this.planReportTemplate) {
        let data = this.planReportTemplate.checkOptions[reportKey];
        this.handleGetCheckOptions(data, reportKey);
      } else if (this.isShare) {
        return getSharePerformanceReportDetailContent(this.shareId, reportKey, this.id)
          .then(res => {
            this.handleGetCheckOptions(res.data, reportKey);
          });
      } else {
        return getPerformanceReportDetailContent(reportKey, this.id)
          .then(res => {
            this.handleGetCheckOptions(res.data, reportKey);
          });
      }
    },
    handleGetCheckOptions(data, reportKey) {
      if (!data || data.length === 0) {
        return;
      }
      let yAxisIndex0List = data.filter(m => m.yAxis2 === -1).map(m => m.groupName);
      yAxisIndex0List = this._unique(yAxisIndex0List);
      this.checkOptions[reportKey] = ['ALL'].concat(yAxisIndex0List);
    },
    getTotalChart() {
      this.totalOption = {};
      this.seriesData = [];
      this.baseOption.yAxis = [];
      this.legend = [];
      let promises = [];
      if (this.planReportTemplate) {
        let chars = [];
        for (let name in this.checkList) {
          let data = this.planReportTemplate.checkOptions[name];
          chars.push({data, 'reportKey': name});
        }
        this.handleGetTotalChart(chars);
      } else {
        for (let name in this.checkList) {
          promises.push(this.getChart(name, this.checkList[name]));
        }
        this.result.loading = Promise.all(promises).then((res) => {
          this.handleGetTotalChart(res);
        })
      }
    },
    handleTemplateGetTotalChart() {

    },
    handleGetTotalChart(res) {
      res = res.filter(v => !!v);
      if (res.length === 0) {
        this.refresh = false;
        this.result.loading = false;
      } else {
        this.refresh = true;
      }
      for (let i = 0; i < res.length; i++) {
        if (i === 0) {
          this.baseOption.yAxis.push({
            name: this.$t('load_test.report.' + res[i].reportKey),
            type: 'value',
            min: 0,
            position: 'left',
            boundaryGap: [0, '100%']
          });
        } else {
          this.baseOption.yAxis.push({
            name: this.$t('load_test.report.' + res[i].reportKey),
            type: 'value',
            min: 0,
            position: 'right',
            nameRotate: 20,
            offset: (i - 1) * 50,
            boundaryGap: [0, '100%']
          });
        }
        this.totalOption = this.generateOption(this.baseOption, res[i].data, i);
      }
      this.totalOption.grid.right = (res.length - 1) * 5 + '%';
      this.changeDataZoom({start: 0, end: 100});
      this.result.loading = false;
    },
    getChart(reportKey, checkList) {
      if (!checkList || checkList.length === 0) {
        return;
      }
      this.totalOption = {};
      if (this.isShare) {
        return getSharePerformanceReportDetailContent(this.shareId, reportKey, this.id)
          .then(res => {
            return this.handleGetChart(res.data, reportKey, checkList);
          });
      } else {
        return getPerformanceReportDetailContent(reportKey, this.id)
          .then(res => {
            return this.handleGetChart(res.data, reportKey, checkList);
          });
      }
    },
    handleGetChart(data, reportKey, checkList) {
      let allData = [];
      let checkAllOption = checkList.indexOf('ALL') > -1;
      if (checkAllOption) {
        let avgOpt = [
          'ResponseTimeChart',
          'ResponseTimePercentilesChart',
          'LatencyChart',
        ];
        let result = groupBy(data, 'xAxis');
        for (const xAxis in result) {
          let yAxis = result[xAxis].map(a => a.yAxis).reduce((a, b) => a + b, 0);
          if (avgOpt.indexOf(reportKey) > -1) {
            yAxis = yAxis / result[xAxis].length;
          }
          allData.push({
            groupName: 'ALL',
            xAxis: xAxis,
            yAxis: yAxis
          });
        }
      }

      //
      data = data.filter(item => {
        if (checkList.indexOf(item.groupName) > -1) {
          return true;
        }
      });

      // 选中了all
      data = data.concat(allData);


      // prefix
      data.forEach(item => {
        item.groupName = this.$t('load_test.report.' + reportKey) + ': ' + item.groupName;
      });
      return {data, reportKey};
    },
    generateOption(option, data, yAxisIndex) {
      let chartData = data;
      let series = {}, xAxis = [];
      chartData.forEach(item => {
        if (!xAxis.includes(item.xAxis)) {
          xAxis.push(item.xAxis);
        }
        xAxis.sort();
        let name = item.groupName;
        if (!this.legend.includes(name)) {
          this.legend.push(name);
          series[name] = [];
        }
        if (series[name]) {
          series[name].splice(xAxis.indexOf(item.xAxis), 0, [item.xAxis, item.yAxis.toFixed(2)]);
        }

      });
      this.$set(option.legend, "data", this.legend);
      this.$set(option.legend, "type", "scroll");
      this.$set(option.legend, "bottom", "10px");
      this.$set(option.xAxis, "data", xAxis);
      for (let name in series) {
        let d = series[name];
        d.sort((a, b) => a[0].localeCompare(b[0]));
        let items = {
          name: name,
          type: 'line',
          data: d,
          yAxisIndex: yAxisIndex,
          smooth: true,
          sampling: 'lttb',
          showSymbol: false,
          animation: !this.export,
        };
        this.seriesData.push(items);
      }
      this.$set(option, "series", this.seriesData);
      return option;
    },
    changeDataZoom(params) {
      let start = params.start / 100;
      let end = params.end / 100;
      if (params.batch) {
        start = params.batch[0].start / 100;
        end = params.batch[0].end / 100;
      }

      let tableData = [];
      for (let i = 0; i < this.seriesData.length; i++) {
        let sub = this.seriesData[i].data, label = this.seriesData[i].name;
        let len = 0;
        let min, avg, max, sum = 0, startTime, endTime;
        for (let j = 0; j < sub.length; j++) {
          let time = sub[j][0];
          let value = Number.parseFloat(sub[j][1]);
          let index = (j / (sub.length - 1)).toFixed(2);
          if (index < start) {
            continue;
          }
          if (index >= end) {
            endTime = time;
            break;
          }

          if (!startTime) {
            startTime = time;
          }

          if (!min && !max) {
            min = max = value;
          }

          if (min > value) {
            min = value;
          }
          if (max < value) {
            max = value;
          }
          sum += value;

          len++; // 实际 len
        }

        avg = (sum / len).toFixed(2);
        tableData.push({label, min, max, avg, startTime, endTime});
      }
      this.tableData = tableData;
    },
    _getChartMax(arr) {
      const max = Math.max(...arr);
      return Math.ceil(max / 4.5) * 5;
    },
    _unique(arr) {
      return Array.from(new Set(arr));
    }
  },
  created() {
    this.id = this.$route.path.split('/')[4];
    this.initTableData();
  },
  watch: {
    '$route'(to) {
      if (to.path.startsWith("/performance/report/view/")) {
        this.id = to.path.split('/')[4];
        this.initTableData();
      }
    },
    report: {
      handler(val) {
        if (!val.status || !val.id) {
          return;
        }
        let status = val.status;
        this.id = val.id;
        if (status === "Running") {
          this.getTotalChart();
        } else if (status === "Completed") {
          this.initTableData();
        }
      },
      deep: true
    },
    planReportTemplate: {
      handler() {
        if (this.planReportTemplate) {
          this.initTableData();
          // todo 勾选无效
          // this.getTotalChart();
        }
      },
      deep: true
    }
  },

};
</script>

<style scoped>
.chart-config {
  width: 100%;
  height: 445px;
}

.test-detail {
  height: calc(100vh - 215px);
  overflow: auto;
}

:deep(.el-checkbox__label ) {
  font-size: 10px !important;
}
</style>
